package group2assignone.dao;

import group2assignone.model.Person;
import group2assignone.view.ClientListView;
import group2assignone.view.UITool;
import java.io.*;
import java.net.*;
import java.util.ArrayList;

/**
 * Client implementation for the client/server code. <br>
 * Communicates with server, registers users and login information.
 * @author group2
 */
public class Client implements ClientComms {

    private static final int DEFAULT_PORT = 5021;
    private static final String DEFAULT_HOST = "127.0.0.1";
    private BufferedReader reader;
    private PrintWriter writer;
    private Socket sock;
    private boolean successful;
    private Person p;
    private static Client instance;
    private ArrayList<String> clientsList;
    private String errorMsg;

    private Client() {
        clientsList = new ArrayList<String>();
        successful = false;
        errorMsg = new String("Unknown error");
    }

    /**
     * Gets instance for this class, as the class is a Singleton
     * @return
     */
    public static Client getInstance() {
        if (instance == null) {
            instance = new Client();
        }
        return instance;
    }

    /**
     * Logs in the user (i.e) Sets up networking with the server and registers the customer.
     * @param p
     * @return (successful or not)
     */
    public boolean login(Person p) {
        this.p = p;
        successful = false;

        setUpNetworking();
        registerCustomer();

        System.out.println("Exiting login function, returning successful");
        return successful;
    }

    private void registerCustomer() {
        String message = new String();
        writer.println(p.getUsername() + "," + p.getPassword());
        writer.flush();
        System.out.println("sending username,password");
        try {
            while ((message = reader.readLine()) == null) {
                System.out.println("waiting");
            }
            if (message.equals("Successful")) {
                successful = true;
                System.out.println("read: " + message);
            } else {
                successful = false;
                errorMsg = "This account is already logged in! Please" +
                        "log out from all seperate computers before trying again";
            }
        } catch (IOException ex) {
            ex.printStackTrace();
            successful = false;
            errorMsg = "Error communicating with server";
        }

    }

    private void setUpNetworking() {
        try {
            sock = new Socket(DEFAULT_HOST, DEFAULT_PORT);
            InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
            reader = new BufferedReader(streamReader);
            writer = new PrintWriter(sock.getOutputStream());
            System.out.println("networking established");
        } catch (IOException ex) {
            ex.printStackTrace();
            successful = false;
            errorMsg = "Error setting up communication with server";
        }
    }

    /**
     * When the user wants to Logout, informs server of logout and closes connection.
     */
    public void logout() {
        writer.println("Logging Out Now");
        writer.flush();
        writer.close();
        try {
            reader.close();
        } catch (IOException ex) {
            ex.printStackTrace();
            errorMsg = "Error communicating with server";
        }
        System.out.println("requesting logout");
    }

    /**
     * Function to receive a list of the currently logged in users from the server.
     * @return
     */
    public boolean receiveClientList() {
        String s = new String();
        boolean b = false;
        try {
            while ((s = reader.readLine()) == null) {
                System.out.println("waiting");
            }
            if (s.equals("Starting To Send")) {
                clientsList.clear();
                while (!(s = reader.readLine()).equals("End Of List")) {
                    clientsList.add(s);
                }
                b = true;
            }
        } catch (IOException ex) {
            b = false;
        }
        return b;
    }

    /**
     * Returns an arraylist of the currently logged in users
     * @return
     */
    public ArrayList<String> getClientList() {
        writer.println("Requesting Client List");
        writer.flush();
        System.out.println("sending request for client list");
        receiveClientList();
        return clientsList;
    }

    /**
     * Starts a new thread for monitoring the view that lists the logged in users.
     * @param view
     */
    public void monitorClientView(ClientListView view) {

        Thread t = new Thread(new MonitorView(view));
        t.start();
    }

    /**
     * gets the current error and returns it as a string
     * @return
     */
    public String getErrorMsg() {
        return errorMsg;
    }

    /**
     * Class which monitors the view that displays a list of the logged in users.
     */
    public class MonitorView implements Runnable {

        ClientListView view;

        /**
         * constructor sets the view in which to monitor
         * @param view
         */
        public MonitorView(ClientListView view) {
            this.view = view;
        }

        /**
         * loops while the connection is still open and gets a user (client) list.
         * <br> Continually updates the view to display the current list. 
         */
        public void run() {
            boolean b = true;
            while (b) {
                b = receiveClientList();
                System.out.println(clientsList);
                view.updateTable(clientsList);
            }
            view.dispose();
            UITool.displayError("Connection Disabled", view);
        }
    }
}
